import {
    ConflictException, ForbiddenException, HttpException, HttpStatus,
    Injectable,
    InternalServerErrorException, Logger,
    NotFoundException
} from "@nestjs/common";
import {UserEntity} from "./user.entity";
import {UserRegisterDto} from "./user.dto";
import {UserDao} from "./user.dao";
import {JwtService} from "@nestjs/jwt";
import {JwtPayload} from "../../common/types/jwt.type";
import {MailService} from "../common/mail/mail.service";
import {RedisService} from "../common/database/redis/redis.service";
import {CODE, USER} from "../../common/constants/redisKey";
import {getRandomNum} from "../../utils/utils";
import {KnowledgeGraphService} from "../knowledgeGraph/knowledgeGraph.service";
import {UserLoginConfig} from "../../common/interfaces/user";
import {UserActionService} from "../common/userAction/userAction.service";

@Injectable()
export class UserService {

    private readonly logger = new Logger(UserService.name);

    constructor(
        // private readonly userRepository:Repository<UserEntity>,
        private readonly userDao: UserDao,
        private readonly jwtService: JwtService,
        private readonly mailService: MailService,
        private readonly redisService: RedisService,
        private readonly knowledgeGraphService: KnowledgeGraphService,
        private readonly userActionService: UserActionService

    ) {
    }

    /**
     * @Description: 根据用户名查找用户信息
     * @author zhaojiuyi
     * @date 2023/4/9
     * @param {string} username 用户名
     */
    async findOne(username: string): Promise<UserEntity> {
        const result = await this.userDao.getUserInfoByName(username);
        if (!result) throw new NotFoundException("用户不存在");
        return result;

    }

    /**
     * @Description: 用户注册
     * @author zhaojiuyi
     * @date 2023/4/9
     * @param {UserRegisterDto} userInfo
     * @return {string}
     */
    async addOne(userInfo: UserRegisterDto): Promise<string> {
        const {code, email} = userInfo
        /* 判断用户名是否已经被注册 */
        const user = await this.userDao.getUserInfoByName(userInfo.username);
        if (user) throw new ConflictException("用户已存在");
        /*验证邮箱验证码*/
        const redisMail = await this.redisService.getValue(`${CODE}:${code}`)
        if (redisMail !== email) throw new ForbiddenException("邮箱验证失败")
        /* 数据插入(用户数据插入mysql，并在知识图谱中创建用户节点) */
        const result = await this.userDao.saveUserInfo(userInfo);
        if (!result) throw new InternalServerErrorException();
        const {username, id} = result
        await this.knowledgeGraphService.createUserNode(username, id)
        return "success";
    }

    /**
     * @Description: 用户登录，生成token
     * @author zhaojiuyi
     * @date 2023/4/9
     * @param {UserEntity} user 用户实体
     * @return {string} token密钥
     */
    async login(user: UserEntity): Promise<string> {
        let version: number = 1
        const {id: userId, username} = user
        const userLoginConfig: UserLoginConfig = await this.redisService.getValue<UserLoginConfig>(`${USER}:${userId}`) as UserLoginConfig
        /* 如果redis中存在数据, 说明用户正在重复登陆, token版本号+1 */
        if (userLoginConfig) {
            version = userLoginConfig.version + 1
        }
        // throw new ForbiddenException("请勿重复登录")
        /* 生成token,并保存用户登录信息到redis */
        const payload: JwtPayload = {version, username, userId};
        const token = this.jwtService.sign(payload);
        const loginConfig: UserLoginConfig = {version, token}
        /* 设置用户登录过期时间,一天 */
        await this.redisService.setValue(`${USER}:${user.id}`, JSON.stringify(loginConfig), 24 * 60 * 60)
        return token;
    }

    /**
     * @Description: 通过查询数据库中是否存在用户历史记录，判断用户是否第一次登录系统
     * @author zhaojiuyi
     * @date 2023/5/17
     * @param {string} userId
     * @return {boolean}
    */
    async isFirstLogin(userId: string):Promise<boolean>{
        const result = await this.userActionService.find({userId})
        return !result.length
    }



    /**
     * @Description: 退出登录
     * @author zhaojiuyi
     * @date 2023/4/15
     * @param {string} userId 用户id
     */
    async logout(userId: string): Promise<any> {
        await this.redisService.delKay(`${USER}:${userId}`)
    }


    /**
     * @Description: 发送邮件
     * @author zhaojiuyi
     * @date 2023/4/15
     */
    async sendMail(mail: string) {
        /* 查询邮箱是否被使用过 */
        const user = await this.userDao.getUserByEmail(mail)
        if (user) throw new ForbiddenException("该邮箱已经被注册")
        /* 该邮箱是否已经发送过验证码 */
        const haveCode = await this.redisService.getValue(`${CODE}:${mail}`)
        if (haveCode) throw new ForbiddenException("请勿重复发送")
        /* 生成验证码 */
        const code = getRandomNum(6)
        await this.mailService.sendCode(mail, code)
        /*发送成功后将验证码和邮箱保存到redis,60秒过期*/
        await this.redisService.setValue(`${CODE}:${code}`, mail, 60)
        return null;
    }


}
